package ua.yandex.skipass;

import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import ua.yandex.collections.MyArrayList;

/**
 *
 * @author Кирилл
 */
public class SkiPassSystem {
    /*
        You can create many instances of SkiPassSystem,
        but it can exist only one TurnstileSystem instance,
        so you can only reset number of turnstiles inside 
        and use if it will already create(or create it otherwise apparently)
        */
    
    private static final int DEFAULT_TURNSTILE = 0;
    
    //private SkiPassSystem system;
    private final TurnstileSystem turnstiles;
    private MyArrayList listOfSkiPassCards;
    
    private MyArrayList permissionAllowed;
    private MyArrayList permissionDenied;
    private int idGenerator = 0;
    
    public SkiPassSystem() {
        turnstiles = TurnstileSystem.getInstance();
        turnstiles.setNumberOfTurnstiles(DEFAULT_TURNSTILE + 1);
        turnstiles.linkToControlSystem(this);
        listOfSkiPassCards = new MyArrayList();
        permissionAllowed = new MyArrayList();
        permissionDenied = new MyArrayList();
    }
    
    public SkiPassSystem(int numberOfTurnstiles) {
        turnstiles = TurnstileSystem.getInstance();
        turnstiles.setNumberOfTurnstiles(numberOfTurnstiles);
        turnstiles.linkToControlSystem(this);
        listOfSkiPassCards = new MyArrayList();
        permissionAllowed = new MyArrayList();
        permissionDenied = new MyArrayList();
    }
    
    public void addSeasonCard(Date activationDate, Date expirationDate) {
        int currentCardId = idGenerator++;
        SkiPassCard card =  new SkiPassSeasonCard(activationDate,
                            expirationDate, currentCardId);
        listOfSkiPassCards.add(card);
    }
    
    public void addWorkdayTimeLimitedCard(Date activationDate,
                    SkiPassTimeShedule time) {
        int currentCardId = idGenerator++;
        SkiPassCard card = new SkiPassWorkdayTimeLimitedCard(activationDate,
                            currentCardId, time);
        listOfSkiPassCards.add(card);
    }
    
    public void addWorkdayRacesLimitedCard(Date activationDate,
                    Date expirationDate, SkiPassRaces races) {
        int currentCardId = idGenerator++;
        SkiPassCard card = new SkiPassWorkdayRacesLimitedCard(activationDate,
                            expirationDate, currentCardId, races);
        listOfSkiPassCards.add(card);
    }
    
    public void addWeekendTimeLimitedCard(Date activationDate,
                    SkiPassTimeShedule time) {
        int currentCardId = idGenerator++;
        SkiPassCard card = new SkiPassWeekendTimeLimitedCard(activationDate,
                                currentCardId, time);
        listOfSkiPassCards.add(card);
    }
    
    public void addWeekendRacesLimitedCard(Date activationDate,
                Date expirationDate, SkiPassRaces races) {
        int currentCardId = idGenerator++;
        SkiPassCard card = new SkiPassWeekendRacesLimitedCard(activationDate,
                            expirationDate, currentCardId, races);
        listOfSkiPassCards.add(card);
    }
    
    private void makePass(SkiPassCard card) {
        if (card instanceof SkiPassWorkdayRacesLimitedCard) {
            ((SkiPassWorkdayRacesLimitedCard) card).decreaseNumberOfRaces();
        }
        if (card instanceof SkiPassWeekendRacesLimitedCard) {
            ((SkiPassWeekendRacesLimitedCard) card).decreaseNumberOfRaces();
        }
    }
    
    public boolean checkSkiPass(int idCard) {
        if (idCard >= listOfSkiPassCards.size() || idCard < 0) {
            throw new OutOfBoundException("Incorrect idCard number");
        }
        return checkSkiPass((SkiPassCard) listOfSkiPassCards.get(idCard));
    }
    
    public boolean checkSkiPass(SkiPassCard card) {
        System.out.println("pointZero!!");
        boolean passIsAllowed = (card != null && card.passIsAllowed());
        if (passIsAllowed) {
            makePass(card);
            permissionAllowed.add(card);
        }
        else {
            permissionDenied.add(card);
        }
        return passIsAllowed;
    }
    
    public static boolean isWorkday() {
        Date currentDate = new Date(System.currentTimeMillis());
        Calendar instance = GregorianCalendar.getInstance();
        instance.setTime(currentDate);
        int day = instance.get(Calendar.DAY_OF_WEEK);
        return day != Calendar.SATURDAY && day != Calendar.SUNDAY;
    }
    public static boolean isWeekend() {
        return !isWorkday();
    }
    
    public int getNumberOfSuccesfullPasses() {
        return permissionAllowed.size();
    }
    
    public int getNumberOfUnsuccesfullPasses() {
        return permissionDenied.size();
    }
    
    private int numberOfCorrespondingTypes(MyArrayList list, SkiPassType type) {
        int numberOfPasses = 0;
        for (int i = 0; i < list.size(); i++) {
            SkiPassCard currentCard = (SkiPassCard) list.get(i);
            if (currentCard.getSkiPassType() == type) {
                numberOfPasses++;
            }
        }
        return numberOfPasses;
    }
    
    public int getNumberOfSuccesfullPasses(SkiPassType type) {
        return numberOfCorrespondingTypes(permissionAllowed, type);
    }
    
    public int getNumberOfUnsuccesfullPasses(SkiPassType type) {
        return numberOfCorrespondingTypes(permissionDenied, type);
    }
    
    public void blockCard(int cardId) {
        SkiPassCard card = (SkiPassCard) listOfSkiPassCards.get(cardId);
        card.block();
    }
    
    public boolean isBlockedCard(int cardId) {
        SkiPassCard card = (SkiPassCard) listOfSkiPassCards.get(cardId);
        return (card.isBlocked());
    }
    public int getNumberOfBlockedCards() {
        int numberOfBlockedCards = 0;
        for (int i = 0; i < this.listOfSkiPassCards.size(); i++) {
            SkiPassCard currentCard = (SkiPassCard) listOfSkiPassCards.get(i);
            if (currentCard.isBlocked()) {
                numberOfBlockedCards++;
            }
        }
        return numberOfBlockedCards;
    }
    
    public int getNumberOfCards() {
        return listOfSkiPassCards.size();
    }
    
    public SkiPassCard getCard(int cardId) {
        return (SkiPassCard) listOfSkiPassCards.get(cardId);
    }
}
